#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

#include "node.h"
#include "timer.h"
#include "monkey.h"
#include "carretel.h"
#include "seta.h"
#include "cube.h"
#include "bitmap_string.h"

static void drawGeneral(Node *this, int x, int y);
static void setRotation(Node *this, int ang);
static void doRender(Node *this);
static void doSetData(Node *this, void *data, int size);
static void setColor(Node *this, float *c);

/** Duplicado pq essa porcaria nao funciona chamada de um arquivo serparado pq ? Who knows :( **/
static void renderBString(float x, float y, float z, void *font, char *string) {
  char *c;
  glRasterPos3f(x, y, z);
  for (c=string; *c != '\0'; c++) {
    glutBitmapCharacter(font, *c);
  }
}

Node *makeNode(node_type t, void *data, int size) {

	Node *n = (Node*) malloc(sizeof(Node));
	if(!n || size < 0)
		return NULL;

	if(t == NONE) {
		strcpy(n->stamp, "None");
		n->type = t;
		n->draw = drawGeneral;
		n->rotate = setRotation;
		n->render = doRender;
		n->color = setColor;
		n->frot = 0;
		n->fval_allocated = 0;
	}
	else if(t == ARRAY) {
		strcpy(n->stamp, "Array");
		n->type = t;
		n->draw = drawGeneral;
		n->rotate = setRotation;
		n->render = doRender;
		n->color = setColor;
		n->frot = 0;
		n->fval_allocated = 0;
	}
	else if(t == SIMPLE_LINKED_LIST) {
		strcpy(n->stamp, "Linked_list");
		n->type = t;
		n->draw = drawGeneral;
		n->rotate = setRotation;
		n->render = doRender;
		n->color = setColor;
		n->frot = 0;
		n->fval_allocated = 0;
	}

	if(data) { // ainda p implementar
		n->data = malloc(sizeof(data) * size);
		n->data_size = size;
	}
	else	
		n->data = NULL;

	return n;
}

void destroyNode(Node *n) {
	if(n)
		free(n);
}

static void drawGeneral(Node *this, int x, int y) {
	this->x = x;
	this->y = y;
	this->width = 50;
	this->height = 50;
}

static void drawArrayNode(Node *this, int x, int y) {


}

static void drawListNode(Node *this, int x, int y) {


}

static void drawDoubleListNode(Node *this, int x, int y) {


}

static void drawBinaryTree(Node  *this, int x, int y) {

}

static void drawTreeNode(Node *this, int x, int y) {


}

static void setRotation(Node *this, int ang) {
	this->rot = ang;
}

static void doCarretel(Node *this) {
	glPushMatrix();
	glColor3f(0.7, 1.0, 0.0);
	// glTranslatef(this->x + 40, this->y + 20, 0);
	glTranslatef(this->x + 40, this->y, 0);
	glScalef(1.8, 1.8, 1.0);
	glRotatef(-90,  0.0, 0.0, 1.0);
	glVertexPointer(3, GL_FLOAT, 0, carretelVerts);
	glNormalPointer(GL_FLOAT, 0, carretelNormals);
	glDrawArrays(GL_TRIANGLES, 0, carretelNumVerts);
	glPopMatrix();
}

static void doSeta(Node *this) {
	glPushMatrix();
	glColor3f(0.7, 0.0, 0.0);
	glTranslatef(this->x + 40, this->y, 0);
	glScalef(1.0, 2.0, 1.0);
	glRotatef(-90,  0.0, 0.0, 1.0);
	glVertexPointer(3, GL_FLOAT, 0, setaVerts);
	glNormalPointer(GL_FLOAT, 0, setaNormals);
	glDrawArrays(GL_TRIANGLES, 0, setaNumVerts);
	glPopMatrix();
}

static void doEsfera(Node *this) {
	glPushMatrix();
	// Sphere
	glColor3f(0.8, 0.0, 1.0);
	glTranslatef(this->x, this->y, 0);
	glutSolidSphere(30, 32, 32);
	glPopMatrix();
}

static void doRender(Node *this) {
	/** como manda o obj2opengl.pl **/
	glEnable(GL_VERTEX_ARRAY);
	glEnable(GL_NORMAL_ARRAY);

	glColor3f(this->cor[0], this->cor[1], this->cor[2]);
	// glRotatef(30, 1.0, 1.0, 0.0);
	// glRecti(this->x, this->y, this->width, this->height);
	// glutSolidCube(25);
	// glutSolidTeapot(20);
	// glTranslatef(this->x, this->y, 0);

	// cube
	glPushMatrix();
	glVertexPointer(3, GL_FLOAT, 0, cubeVerts);
	glNormalPointer(GL_FLOAT, 0, cubeNormals);
	glTranslatef(this->x, this->y, 0);
	glDrawArrays(GL_TRIANGLES, 0, cubeNumVerts);
	glPopMatrix();

	// carretel 
	if(this->type == ARRAY)
		doCarretel(this);
	// else if(node->type == SIMPLE_LINKED_LIST)
	else {
		doSeta(this);
		// if(this->index)
		//	doEsfera(this);
	}

	// Text
	if(this->fval_allocated) {
		glPushMatrix();
		glColor3f(1.0, 1.0, 1.0);
		glDisable(GL_LIGHTING);  
		renderBString(this->x, this->y - 45, 3, GLUT_BITMAP_TIMES_ROMAN_24, "Test");
		glEnable(GL_LIGHTING);  
		glPopMatrix();
	}
	/***/
}

void setColor(Node *this, float *c) {
	this->cor[0] = c[0];
	this->cor[1] = c[1];
	this->cor[2] = c[2];
}

